package com.artisan.springuitls.demos;

import org.springframework.stereotype.Component;
import org.springframework.util.ConcurrentReferenceHashMap;

import java.util.Map;

/**
 * ConcurrentReferenceHashMap 工具类演示
 * 功能：并发弱引用 Map
 * 优势：基于弱引用的并发 Map，自动回收无引用对象，比 ConcurrentHashMap 更省内存
 * 
 * ⚠️ 提醒：仅用于非关键缓存，生产级缓存用 Spring Cache + Caffeine
 */
@Component
public class ConcurrentReferenceHashMapDemo {

    /**
     * 场景：实现轻量级缓存
     */
    public void demonstrateLightweightCache() {
        System.out.println("\n========== ConcurrentReferenceHashMap Demo ==========");
        
        // ✅ 弱引用缓存：当对象无强引用时自动回收
        Map<String, User> cache = new ConcurrentReferenceHashMap<>(
            64, // 初始容量
            ConcurrentReferenceHashMap.ReferenceType.WEAK // 弱引用
        );
        
        // 添加对象到缓存
        User user1 = new User("张三", 25);
        cache.put("user1", user1);
        System.out.println("✓ 缓存中存在 user1: " + (cache.get("user1") != null));
        
        // 模拟对象被 GC（去除强引用）
        user1 = null;
        System.gc(); // 建议 JVM 执行垃圾回收
        
        // 等待 GC 完成
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("✓ GC 后缓存中存在 user1: " + (cache.get("user1") != null));
    }

    /**
     * 演示不同引用类型
     */
    public void demonstrateReferenceTypes() {
        System.out.println("\n--- 不同引用类型 ---");
        
        // 1. 软引用（SOFT）：内存不足时回收
        System.out.println("✓ 软引用缓存：内存不足时回收");
        System.out.println("  ReferenceType.SOFT");
        
        // 2. 弱引用（WEAK）：GC 时立即回收
        System.out.println("✓ 弱引用缓存：GC 时立即回收");
        System.out.println("  ReferenceType.WEAK");
        
        System.out.println();
    }

    /**
     * 演示基础操作
     */
    public void demonstrateBasicOperations() {
        System.out.println("\n--- 基础操作 ---");
        
        Map<String, String> cache = new ConcurrentReferenceHashMap<>();
        
        // 1. 添加元素
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        System.out.println("✓ 添加元素，大小: " + cache.size());
        
        // 2. 获取元素
        String value = cache.get("key1");
        System.out.println("✓ 获取 key1: " + value);
        
        // 3. 检查存在
        boolean exists = cache.containsKey("key2");
        System.out.println("✓ 包含 key2: " + exists);
        
        // 4. 删除元素
        cache.remove("key3");
        System.out.println("✓ 删除 key3 后大小: " + cache.size());
        
        // 5. 遍历
        System.out.println("✓ 遍历缓存:");
        cache.forEach((key, val) -> System.out.println("  - " + key + " = " + val));
        
        System.out.println();
    }

    /**
     * 演示并发操作
     */
    public void demonstrateConcurrentOperations() throws InterruptedException {
        System.out.println("\n--- 并发操作 ---");
        
        Map<String, Integer> cache = new ConcurrentReferenceHashMap<>();
        
        // 创建多个线程同时操作缓存
        Thread[] threads = new Thread[5];
        for (int i = 0; i < threads.length; i++) {
            final int threadId = i;
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    String key = "key-" + threadId + "-" + j;
                    cache.put(key, j);
                }
            });
            threads[i].start();
        }
        
        // 等待所有线程完成
        for (Thread thread : threads) {
            thread.join();
        }
        
        System.out.println("✓ 并发写入完成，缓存大小: " + cache.size());
        System.out.println("✓ ConcurrentReferenceHashMap 是线程安全的");
        
        System.out.println();
    }

    /**
     * 实际应用场景：类加载器缓存
     */
    public void demonstrateClassLoaderCache() {
        System.out.println("\n--- 类加载器缓存场景 ---");
        
        // 模拟类加载器缓存（Spring 内部使用此机制）
        Map<String, Class<?>> classCache = new ConcurrentReferenceHashMap<>(
            256,
            ConcurrentReferenceHashMap.ReferenceType.SOFT
        );
        
        // 缓存类信息
        classCache.put("java.lang.String", String.class);
        classCache.put("java.lang.Integer", Integer.class);
        classCache.put("java.util.ArrayList", java.util.ArrayList.class);
        
        System.out.println("✓ 类缓存大小: " + classCache.size());
        System.out.println("✓ 获取 String 类: " + classCache.get("java.lang.String"));
        
        System.out.println("✓ 使用场景：");
        System.out.println("  - 反射类缓存");
        System.out.println("  - ClassLoader 类信息缓存");
        System.out.println("  - 避免重复加载类");
        
        System.out.println();
    }

    /**
     * 实际应用场景：方法元数据缓存
     */
    public void demonstrateMethodMetadataCache() {
        System.out.println("\n--- 方法元数据缓存场景 ---");
        
        // 模拟方法元数据缓存
        Map<String, MethodMetadata> methodCache = new ConcurrentReferenceHashMap<>(
            128,
            ConcurrentReferenceHashMap.ReferenceType.WEAK
        );
        
        // 缓存方法元数据
        methodCache.put("UserService.findById", new MethodMetadata("findById", "查询用户"));
        methodCache.put("UserService.save", new MethodMetadata("save", "保存用户"));
        methodCache.put("UserService.delete", new MethodMetadata("delete", "删除用户"));
        
        System.out.println("✓ 方法缓存大小: " + methodCache.size());
        System.out.println("✓ 获取方法: " + methodCache.get("UserService.findById"));
        
        System.out.println("✓ 使用场景：");
        System.out.println("  - AOP 方法拦截元数据");
        System.out.println("  - 注解扫描结果缓存");
        System.out.println("  - 反射方法调用缓存");
        
        System.out.println();
    }

    /**
     * 与 ConcurrentHashMap 对比
     */
    public void compareWithConcurrentHashMap() {
        System.out.println("\n--- 与 ConcurrentHashMap 对比 ---");
        
        System.out.println("✓ ConcurrentHashMap:");
        System.out.println("  - 特点：强引用，不会自动回收");
        System.out.println("  - 优势：性能高，数据不丢失");
        System.out.println("  - 适用：需要持久化缓存的场景");
        System.out.println("");
        System.out.println("✓ ConcurrentReferenceHashMap:");
        System.out.println("  - 特点：弱/软引用，自动回收");
        System.out.println("  - 优势：省内存，避免内存泄漏");
        System.out.println("  - 适用：临时缓存、元数据缓存");
        System.out.println("");
        System.out.println("✓ 选择建议:");
        System.out.println("  - 重要数据 => ConcurrentHashMap");
        System.out.println("  - 临时缓存 => ConcurrentReferenceHashMap");
        System.out.println("  - 生产缓存 => Spring Cache + Caffeine");
        
        System.out.println();
    }

    /**
     * 性能和内存测试
     */
    public void demonstratePerformanceTest() {
        System.out.println("\n--- 性能和内存测试 ---");
        
        // 创建大量对象
        Map<String, byte[]> cache = new ConcurrentReferenceHashMap<>(
            1000,
            ConcurrentReferenceHashMap.ReferenceType.SOFT
        );
        
        System.out.println("✓ 添加 1000 个对象到缓存...");
        for (int i = 0; i < 1000; i++) {
            cache.put("key-" + i, new byte[1024]); // 每个 1KB
        }
        
        System.out.println("✓ 缓存大小: " + cache.size());
        System.out.println("✓ 估计内存: ~" + (cache.size() * 1024 / 1024) + " MB");
        
        // 触发 GC
        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("✓ GC 后缓存大小: " + cache.size());
        System.out.println("✓ 软引用在内存充足时不会被回收");
        
        System.out.println("==========================================\n");
    }

    /**
     * 模拟 User 对象
     */
    static class User {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{name='" + name + "', age=" + age + "}";
        }
    }

    /**
     * 模拟方法元数据
     */
    static class MethodMetadata {
        private String methodName;
        private String description;

        public MethodMetadata(String methodName, String description) {
            this.methodName = methodName;
            this.description = description;
        }

        @Override
        public String toString() {
            return "MethodMetadata{method='" + methodName + "', desc='" + description + "'}";
        }
    }

    /**
     * 最佳实践
     */
    public void printBestPractices() {
        System.out.println("\n========== 最佳实践 ==========");
        System.out.println("✓ 1. 仅用于非关键临时缓存");
        System.out.println("✓ 2. 软引用适合内存敏感场景");
        System.out.println("✓ 3. 弱引用适合短生命周期对象");
        System.out.println("✓ 4. 不要用于存储重要业务数据");
        System.out.println("✓ 5. 生产级缓存使用 Caffeine/Redis");
        System.out.println("✓ 6. Spring 内部广泛使用此类");
        System.out.println("✓ 7. 理解引用类型再使用");
        System.out.println("==========================================\n");
    }
}

